#ifndef _SYSREGS_H
#define _SYSREGS_H

#include <type.h>

/*
macros about SCTLR_ELX (system control register)
*/

/* Common SCTLR_ELx flags. */
#define SCTLR_ELx_DSSBS	(BITUL(44))
#define SCTLR_ELx_ENIA	(BITUL(31))
#define SCTLR_ELx_ENIB	(BITUL(30))
#define SCTLR_ELx_ENDA	(BITUL(27))
#define SCTLR_ELx_EE    (BITUL(25))
#define SCTLR_ELx_IESB	(BITUL(21))
#define SCTLR_ELx_WXN	(BITUL(19))
#define SCTLR_ELx_ENDB	(BITUL(13))
#define SCTLR_ELx_I	(BITUL(12))
#define SCTLR_ELx_SA	(BITUL(3))
#define SCTLR_ELx_C	(BITUL(2))
#define SCTLR_ELx_A	(BITUL(1))
#define SCTLR_ELx_M	(BITUL(0))

/* SCTLR_EL1 specific flags. */
#define SCTLR_EL1_UCI		(BITUL(26))
#define SCTLR_EL1_E0E		(BITUL(24))
#define SCTLR_EL1_SPAN		(BITUL(23))
#define SCTLR_EL1_NTWE		(BITUL(18))
#define SCTLR_EL1_NTWI		(BITUL(16))
#define SCTLR_EL1_UCT		(BITUL(15))
#define SCTLR_EL1_DZE		(BITUL(14))
#define SCTLR_EL1_UMA		(BITUL(9))
#define SCTLR_EL1_SED		(BITUL(8))
#define SCTLR_EL1_ITD		(BITUL(7))
#define SCTLR_EL1_CP15BEN	(BITUL(5))
#define SCTLR_EL1_SA0		(BITUL(4))

/* macros for EL3 eret to EL2 */
#define SCTLR_EL2_RES1 \
	((BITUL(4))  | (BITUL(5))  | (BITUL(11)) | (BITUL(16)) | \
	(BITUL(18)) | (BITUL(22)) | (BITUL(23)) | (BITUL(28)) | \
	(BITUL(29)))
#define ENDIAN_SET_EL2		0
#define SCTLR_EL2_VALUE_MMU_DISABLED (SCTLR_EL2_RES1 | ENDIAN_SET_EL2)

#define SCR_RESERVED (3 << 4)
#define SCR_RW (1 << 10)
#define SCR_NS (1 << 0)
#define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_NS)

/* macros for EL2 eret to EL1 */
#define SCTLR_EL1_RES1 \
	((BITUL(11)) | (BITUL(20)) | (BITUL(22)) | (BITUL(28)) | \
	(BITUL(29)))
#define ENDIAN_SET_EL1		0
#define SCTLR_EL1_VALUE_MMU_DISABLED (SCTLR_EL1_RES1 | ENDIAN_SET_EL1)

#define HCR_RW (1 << 31)

/* spsr set for eret*/
#define SPSR_MASK_ALL (7 << 6)
#define SPSR_EL1h (5 << 0)
#define SPSR_EL2h (9 << 0)
#define SPSR_EL1 (SPSR_MASK_ALL | SPSR_EL1h)
#define SPSR_EL2 (SPSR_MASK_ALL | SPSR_EL2h)

/* Current Exception Level values, as contained in CurrentEL */
#define CurrentEL_EL1 (1 << 2)
#define CurrentEL_EL2 (2 << 2)
#define CurrentEL_EL3 (3 << 2)


#define read_sysreg(reg) ({ \
		u64 _val; \
		asm volatile("mrs %0," #reg \
		: "=r"(_val)); \
		_val; \
})

#define write_sysreg(val, reg) ( { \
		u64 _val = (u64)val; \
		asm volatile("msr " #reg ", %0" \
		:: "rZ"(_val)); \
} )

#define get_currentel() ({ \
		u64 _val; \
		asm volatile("mrs %0, CurrentEL" \
		: "=r"(_val)); \
		_val; \
})

#endif
